package com.wuzuqing.android.eightdiagrams.term;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solar {
    public static int J2000 = 2451545;
    public int year;
    public int month;
    public int day;
    public int hour;
    public int minute;
    public int second;
    public ExactDate calendar;

    public Solar(int year, int month, int day, int hour, int minute, int second) {
        this.year = year;
        this.month = month;
        this.day = day;
        this.hour = hour;
        this.minute = minute;
        this.second = second;
        calendar = ExactDate.fromYmdHms(year, month, day, hour, minute, second);
        lunar = null;
    }

    public int getYear() {
        return this.year;
    }

    public int getMonth() {
        return this.month;
    }

    public int getDay() {
        return this.day;
    }

    public int getHour() {
        return this.hour;
    }

    public int getMinute() {
        return this.minute;
    }

    public int getSecond() {
        return this.second;
    }

    public int getWeek() {
        return this.calendar.getWeek();
    }

    public String getWeekInChinese() {
        return SolarUtil.WEEK[this.getWeek()];
    }

    /**
     * 获取当天的阳历周
     *
     * @param start 星期几作为一周的开始，1234560分别代表星期一至星期天
     */
    public SolarWeek getSolarWeek(int start) {
        return SolarWeek.fromDate(this.calendar, start);
    }

    public boolean isLeapYear() {
        return SolarUtil.isLeapYear(this.year);
    }

    public List<String> getFestivals() {
        List<String> l = new ArrayList<>();
        String f = SolarUtil.FESTIVAL.get(this.month + '-' + this.day);
        if (f != null) {
            l.add(f);
        }
        int weeks = (int) Math.ceil(this.day / 7);
        int week = this.getWeek();
        f = SolarUtil.WEEK_FESTIVAL.get(this.month + '-' + weeks + '-' + week);
        if (f != null) {
            l.add(f);
        }
        return l;
    }

    public List<String> getOtherFestivals() {
        List<String> l = new ArrayList<>();
        String[] fs = SolarUtil.OTHER_FESTIVAL.get(this.month + '-' + this.day);
        if (fs != null) {
            l.addAll(Arrays.asList(fs));
        }
        return l;
    }

    public String getXingzuo() {
        return this.getXingZuo();
    }

    public String getXingZuo() {
        int index = 11;
        int y = this.month * 100 + this.day;
        if (y >= 321 && y <= 419) {
            index = 0;
        } else if (y >= 420 && y <= 520) {
            index = 1;
        } else if (y >= 521 && y <= 621) {
            index = 2;
        } else if (y >= 622 && y <= 722) {
            index = 3;
        } else if (y >= 723 && y <= 822) {
            index = 4;
        } else if (y >= 823 && y <= 922) {
            index = 5;
        } else if (y >= 923 && y <= 1023) {
            index = 6;
        } else if (y >= 1024 && y <= 1122) {
            index = 7;
        } else if (y >= 1123 && y <= 1221) {
            index = 8;
        } else if (y >= 1222 || y <= 119) {
            index = 9;
        } else if (y <= 218) {
            index = 10;
        }
        return SolarUtil.XINGZUO[index];
    }


    public String toYmd() {
        int d = this.day;
        if (this.year == 1582 && this.month == 10) {
            if (d >= 5) {
                d += 10;
            }
        }
        return String.format("%04d-%02d-%02d", this.year, this.month, d);
    }

    public String toYmdHms() {
        return this.toYmd() + String.format(" %02d:%02d:%02d", this.hour, this.minute, this.second);
    }

    @Override
    public String toString() {
        return this.toYmd();
    }

    public String toFullString() {
        StringBuilder s = new StringBuilder(this.toYmdHms());
        if (this.isLeapYear()) {
            s.append(" 闰年");
        }
        s.append(" 星期").append(getWeekInChinese());
        List<String> festivals = this.getFestivals();
        for (int i = 0, j = festivals.size(); i < j; i++) {
            s.append(" (").append(festivals.get(i)).append(")");
        }
        s.append(" ").append(this.getXingZuo()).append("座");
        return s.toString();
    }

    public Solar next(int days, boolean onlyWorkday) {
        ExactDate date = ExactDate.fromYmdHms(this.year, this.month, this.day, this.hour, this.minute,
                this.second);
        if (0 != days) {
            if (!onlyWorkday) {
                date.setDate(date.getDate() + days);
            } else {
                int rest = Math.abs(days);
                int add = days < 1 ? -1 : 1;
                while (rest > 0) {
                    date.setDate(date.getDate() + add);
                    boolean work = true;
                    HolidayUtil holiday = HolidayUtil.getHoliday(date.getYear(), date.getMonth(), date.getDate());
                    if (holiday==null) {
                        int week = date.getDay();
                        if (0 == week || 6 == week) {
                            work = false;
                        }
                    } else {
                        work = holiday.isWork();
                    }
                    if (work) {
                        rest--;
                    }
                }
            }
        }
        return fromDate(date);
    }
    Lunar lunar;

    public Lunar getLunar() {
        if (lunar == null) {
            lunar = Lunar.fromDate(this.calendar);
        }
        return lunar;
    }

    public double getJulianDay() {
        int y = this.year;
        int m = this.month;
        double d = this.day + ((this.second / 60f + this.minute) / 60 + this.hour) / 24;
        int n = 0;
        boolean g = false;
        if (y * 372 + m * 31 + Math.floor(d) >= 588829) {
            g = true;
        }
//        console.log(y,m,d,n);
        if (m <= 2) {
            m += 12;
            y--;
        }
        if (g) {
            n = (int) Math.floor(y / 100d);
            n = (int) (2 - n + Math.floor(n / 4d));
        }
        return (Math.floor(365.25 * (y + 4716)) + Math.floor(30.6001 * (m + 1)) + d + n - 1524.5);
    }

    public ExactDate getCalendar() {
        return this.calendar;
    }



    public static Solar fromYmd(int y,int m,int d) {
        return _fromYmdHms(y, m, d, 0, 0, 0);
    }
    public static Solar fromYmdHms(int y,int m,int d,int hour,int minute,int second) {
        return _fromYmdHms(y, m, d, hour, minute, second);
    }
    public static Solar  fromDate(ExactDate date) {
        return _fromYmdHms(date.getYear(), date.getMonth(),
                date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
    }
    public static Solar fromJulianDay(double julianDay) {
        return _fromJulianDay(julianDay);
    }

    private static Solar _fromJulianDay (double julianDay) {
        double d = Math.floor(julianDay + 0.5);
        double f = julianDay + 0.5 - d;
        double c;

        if (d >= 2299161) {
            c = Math.floor((d - 1867216.25) / 36524.25);
            d += 1 + c - Math.floor(c / 4);
        }
        d += 1524;
        int year = (int) Math.floor((d - 122.1) / 365.25);
        d -= Math.floor(365.25 * year);
        int month = (int) Math.floor(d / 30.601);
        d -= Math.floor(30.601 * month);
        int day = (int) d;
        if (month > 13) {
            month -= 13;
            year -= 4715;
        } else {
            month -= 1;
            year -= 4716;
        }
        f *= 24;
        int hour = (int) Math.floor(f);

        f -= hour;
        f *= 60;
        int minute = (int) Math.floor(f);

        f -= minute;
        f *= 60;
        int second = (int) Math.round(f);
        return _fromYmdHms(year, month, day, hour, minute, second);
    };

    private static Solar _fromYmdHms(int y,int m,int d,int hour,int minute,int second){
        if (y == 1582 && m == 10) {
            if (d >= 15) {
                d -= 10;
            }
        }
        return new Solar(y,m,d,hour,minute,second);
    }
}
